package cn.broadsense.biz.service.impl;

import cn.broadsense.biz.convert.ChannelConvert;
import cn.broadsense.biz.domain.Channel;
import cn.broadsense.biz.domain.ChannelGovernance;
import cn.broadsense.biz.domain.ChannelGovernanceDetails;
import cn.broadsense.biz.enums.ChannelFieldEnum;
import cn.broadsense.biz.mapper.ChannelGovernanceMapper;
import cn.broadsense.biz.mapper.ChannelMapper;
import cn.broadsense.biz.service.ChannelGovernanceDetailsService;
import cn.broadsense.biz.service.ChannelGovernanceService;
import cn.broadsense.biz.service.ChannelService;
import cn.broadsense.biz.vo.ChannelGovernanceRuleCriteriaVo;
import cn.broadsense.biz.vo.ChannelGovernanceVo;
import cn.broadsense.common.core.redis.RedisCache;
import cn.broadsense.common.exception.ServiceException;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author bs
 * @description 针对表【t_channel_governance(点位治理列表)】的数据库操作Service实现
 * @createDate 2024-04-11 17:14:59
 */
@AllArgsConstructor
@Service
public class ChannelGovernanceServiceImpl extends ServiceImpl<ChannelGovernanceMapper, ChannelGovernance> implements ChannelGovernanceService {

    private final ThreadPoolTaskExecutor threadPoolTaskExecutor;

    private final ChannelMapper channelMapper;

    private final ChannelGovernanceDetailsService channelGovernanceDetailsService;

    private final RedisCache redisCache;

    private final ChannelService channelService;


    private final ChannelConvert channelConvert;

    private final String REDIS_KEY_SYNC = "tm:governance:sync";
    private final String REDIS_KEY_SYNC_ALL = "tm:governance:sync:all";

    final List<String> criteriaStrList = CollUtil.newArrayList("and", "or");


    @Override
    public void governanceSetting(ChannelGovernanceVo channelGovernanceVo) {
        if (redisCache.hasKey(REDIS_KEY_SYNC)) {
            throw new ServiceException("当前已有视频点位数据正在治理中，请稍后再试");
        }
        redisCache.setCacheObject(REDIS_KEY_SYNC, "1");
        redisCache.expire(REDIS_KEY_SYNC, 120);

        ChannelGovernance channelGovernance = new ChannelGovernance();
        checkParam(channelGovernanceVo);
        channelGovernance.setFilterCriteria(channelGovernanceVo);
        if (CollUtil.isEmpty(channelGovernanceVo.getChannelIds())) {
            QueryWrapper<Channel> query = new QueryWrapper<>();
            query.eq("del_flag", "0");
            channelGovernance.setDataQty(channelMapper.selectCount(query).intValue());
        } else {
            channelGovernance.setDataQty(channelGovernanceVo.getChannelIds().size());
        }
        try {
            boolean save = this.save(channelGovernance);
            if (save) {
                threadPoolTaskExecutor.execute(() -> {
                    handlerData(channelGovernanceVo, channelGovernance);
                });
            }
        } catch (Exception e) {
            redisCache.deleteObject(REDIS_KEY_SYNC);
            throw e;
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long id) {
        this.removeById(id);
        channelGovernanceDetailsService.remove(new QueryWrapper<ChannelGovernanceDetails>().eq("channel_governance_id", id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeSync(Long id) {
        //修改状态
        LambdaUpdateWrapper<ChannelGovernance> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(ChannelGovernance::getId, id);
        lambdaUpdateWrapper.eq(ChannelGovernance::getSyncStatus, 0);
        lambdaUpdateWrapper.set(ChannelGovernance::getSyncStatus, 1);
        boolean update = this.update(lambdaUpdateWrapper);
        if (!update) {
            throw new ServiceException("数据不存在,或者数据已同步");
        }
        List<ChannelGovernanceDetails> list = channelGovernanceDetailsService.lambdaQuery().eq(ChannelGovernanceDetails::getChannelGovernanceId, id)
                .in(ChannelGovernanceDetails::getChangeStatus, 1, 2).list();
        if (CollUtil.isEmpty(list)) {
            return;
        }
        Map<Integer, List<ChannelGovernanceDetails>> listMap = list.stream().collect(Collectors.groupingBy(ChannelGovernanceDetails::getChangeStatus));
        //变更数据
        List<ChannelGovernanceDetails> changeList = listMap.get(1);
        List<ChannelGovernanceDetails> deleteList = listMap.get(2);
        if (CollUtil.isNotEmpty(changeList)) {
            List<Channel> updateChannelList = new ArrayList<>();
            Date date = new Date();
            List<ChannelGovernanceDetails> updateList = new ArrayList<>();
            changeList.forEach(channelGovernanceDetails -> {
                ChannelGovernanceDetails updateDetails = new ChannelGovernanceDetails();
                updateDetails.setSyncTime(date);
                updateDetails.setId(channelGovernanceDetails.getId());
                updateList.add(updateDetails);
                Channel channel = JSONObject.parseObject(channelGovernanceDetails.getChangeJson(), Channel.class);
                channel.setId(channelGovernanceDetails.getChannelId());
                updateChannelList.add(channel);
            });
            channelService.updateBatchById(updateChannelList, 500);

            channelGovernanceDetailsService.updateBatchById(updateList, 500);
        }
        //删除点位
        if (CollUtil.isNotEmpty(deleteList)) {
            channelMapper.deleteBatchIds(deleteList.stream().map(ChannelGovernanceDetails::getChannelId).collect(Collectors.toList()));
        }
    }

    @Override
    public void changeSyncAll() {
        if (redisCache.hasKey(REDIS_KEY_SYNC_ALL)) {
            throw new ServiceException("数据全量同步同步中，请稍后再试");
        }
        redisCache.setCacheObject(REDIS_KEY_SYNC_ALL, "1");
        redisCache.expire(REDIS_KEY_SYNC_ALL, 300);
        threadPoolTaskExecutor.execute(() -> {
            try {
                List<ChannelGovernance> list = this.lambdaQuery().eq(ChannelGovernance::getSyncStatus, 0).list();
                if (CollUtil.isEmpty(list)) {
                    return;
                }
                ChannelGovernanceService governanceService = SpringUtil.getBean(ChannelGovernanceService.class);
                list.forEach(channelGovernance -> {
                    try {
                        governanceService.changeSync(channelGovernance.getId());
                    } catch (Exception e) {
                        log.error("同步错误：{}", e);
                    }
                });
            } catch (Exception e) {
                log.error("同步错误：{}", e);
            } finally {
                redisCache.deleteObject(REDIS_KEY_SYNC_ALL);
            }
        });
    }

    /**
     * 数据处理
     *
     * @param channelGovernanceVo
     * @param channelGovernance
     */
    private void handlerData(ChannelGovernanceVo channelGovernanceVo, ChannelGovernance channelGovernance) {
        try {
            List<Channel> repeatList = new ArrayList<>();
            List<Channel> emptyList = new ArrayList<>();
            List<Channel> ruleList = new ArrayList<>();
            Map<Long, ChannelGovernanceDetails> governanceDetailsMap = new HashMap<>();
            Long channelGovernanceId = channelGovernance.getId();
            //重复数据
            if (StrUtil.isNotBlank(channelGovernanceVo.getRepeatCriteria())) {
                if (!ChannelFieldEnum.CHANNEL_NUM.getFiledNameDb().equals(channelGovernanceVo.getRepeatCriteria())) {
                    try {
                        repeatList = channelMapper.filterRepeatList(channelGovernanceVo.getRepeatCriteria(), channelGovernanceVo.getChannelIds());
                    } catch (Exception e) {
                        log.error("重复数据处理失败：{}", e);
                    }
                }
            }
            //空值数据
            if (StrUtil.isNotBlank(channelGovernanceVo.getEmptyCriteria())) {
                List<String> empList = new ArrayList<>();
                //替换gps
                channelGovernanceVo.getEmptyList().forEach(item -> {
                    if (ChannelFieldEnum.GPS_X.getFiledNameDb().equals(item)) {
                        empList.add("gps_x");
                        empList.add("gps_y");
                    } else if (!ChannelFieldEnum.CHANNEL_NUM.getFiledNameDb().equals(item)) {
                        empList.add(item);
                    }
                });
                if (CollUtil.isNotEmpty(empList)) {
                    try {
                        emptyList = channelMapper.filterEmptyList(channelGovernanceVo.getEmptyCriteria(), empList, channelGovernanceVo.getChannelIds());
                    } catch (Exception e) {
                        log.error("空值数据错误：{}", e);
                    }
                }
            }
            //规则过滤数据
            if (StrUtil.isNotBlank(channelGovernanceVo.getRuleCriteria())) {
                List<ChannelGovernanceRuleCriteriaVo> ruleList1 = new ArrayList<>();
                //替换gps
                channelGovernanceVo.getRuleList().forEach(item -> {
                    if (ChannelFieldEnum.GPS_X.getFiledNameDb().equals(item.getFieldName())) {
                        List<String> stringList = StrUtil.split(item.getFieldValue(), ",");
                        ChannelGovernanceRuleCriteriaVo channelGovernanceRuleCriteriaVo = new ChannelGovernanceRuleCriteriaVo();
                        channelGovernanceRuleCriteriaVo.setCriteria(item.getCriteria());
                        channelGovernanceRuleCriteriaVo.setFieldName("gps_x");
                        channelGovernanceRuleCriteriaVo.setFieldValue(stringList.get(0));
                        ruleList1.add(channelGovernanceRuleCriteriaVo);
                        ChannelGovernanceRuleCriteriaVo channelGovernanceRuleCriteriaVo1 = new ChannelGovernanceRuleCriteriaVo();
                        channelGovernanceRuleCriteriaVo1.setCriteria(item.getCriteria());
                        channelGovernanceRuleCriteriaVo1.setFieldName("gps_y");
                        channelGovernanceRuleCriteriaVo1.setFieldValue(stringList.get(1));
                        ruleList1.add(channelGovernanceRuleCriteriaVo1);

                    } else {
                        ruleList1.add(item);
                    }
                });
                if (CollUtil.isNotEmpty(ruleList1)) {
                    try {
                        ruleList = channelMapper.filterRuleList(channelGovernanceVo.getRuleCriteria(), ruleList1, channelGovernanceVo.getChannelIds());
                    } catch (Exception e) {
                        log.error("规则数据错误：{}", e);
                    }
                }

            }
            if (CollUtil.isNotEmpty(repeatList)) {
                repeatList.forEach(channel -> {
                    ChannelGovernanceDetails channelGovernanceDetails = new ChannelGovernanceDetails();
                    channelGovernanceDetails.setChannelCode(channel.getChannelCode());
                    channelGovernanceDetails.setChannelId(channel.getId());
                    channelGovernanceDetails.setChannelName(channel.getChannelName());
                    channelGovernanceDetails.setChannelGovernanceId(channelGovernanceId);
                    channelGovernanceDetails.setRepeatStatus(1);
                    governanceDetailsMap.put(channel.getId(), channelGovernanceDetails);
                });
            }
            if (CollUtil.isNotEmpty(emptyList)) {
                emptyList.forEach(channel -> {
                    ChannelGovernanceDetails channelGovernanceDetails = governanceDetailsMap.get(channel.getId());
                    if (channelGovernanceDetails == null) {
                        channelGovernanceDetails = new ChannelGovernanceDetails();
                        channelGovernanceDetails.setChannelGovernanceId(channelGovernanceId);
                        channelGovernanceDetails.setChannelName(channel.getChannelName());
                        channelGovernanceDetails.setChannelCode(channel.getChannelCode());
                        channelGovernanceDetails.setChannelId(channel.getId());
                    }
                    channelGovernanceDetails.setEmptyStatus(1);
                    governanceDetailsMap.put(channel.getId(), channelGovernanceDetails);
                });
            }

            if (CollUtil.isNotEmpty(ruleList)) {
                ruleList.forEach(channel -> {
                    ChannelGovernanceDetails channelGovernanceDetails = governanceDetailsMap.get(channel.getId());
                    if (channelGovernanceDetails == null) {
                        channelGovernanceDetails = new ChannelGovernanceDetails();
                        channelGovernanceDetails.setChannelGovernanceId(channelGovernanceId);
                        channelGovernanceDetails.setChannelCode(channel.getChannelCode());
                        channelGovernanceDetails.setChannelName(channel.getChannelName());
                        channelGovernanceDetails.setChannelId(channel.getId());
                    }
                    channelGovernanceDetails.setRuleStatus(1);
                    governanceDetailsMap.put(channel.getId(), channelGovernanceDetails);
                });
            }

            //更新库数据
            ChannelGovernance updateGovernance = new ChannelGovernance();
            updateGovernance.setId(channelGovernance.getId());
            updateGovernance.setRepeatQty(repeatList.size());
            updateGovernance.setEmptyQty(emptyList.size());
            updateGovernance.setRuleQty(ruleList.size());
            updateGovernance.setResultQty(governanceDetailsMap.size());
            this.baseMapper.updateById(updateGovernance);
            if (CollUtil.isNotEmpty(governanceDetailsMap)) {
                channelGovernanceDetailsService.saveBatch(governanceDetailsMap.values());
            }
        } finally {
            redisCache.deleteObject(REDIS_KEY_SYNC);
        }
    }


    /**
     * 校验参数
     *
     * @param channelGovernanceVo
     */
    private void checkParam(ChannelGovernanceVo channelGovernanceVo) {
        // 分别校验空值条件、规则条件等，提高代码的可读性和维护性
        validateEmptyList(channelGovernanceVo);
        validateRuleList(channelGovernanceVo);
    }

    /**
     * 校验空值条件
     *
     * @param channelGovernanceVo
     */
    private void validateEmptyList(ChannelGovernanceVo channelGovernanceVo) {
        boolean isEmpty = CollUtil.isEmpty(channelGovernanceVo.getEmptyList()) && StrUtil.isBlank(channelGovernanceVo.getRepeatCriteria()) && CollUtil.isEmpty(channelGovernanceVo.getRuleList());
        if (isEmpty) {
            redisCache.deleteObject(REDIS_KEY_SYNC);
            throw new ServiceException("必须要添加一个条件才能治理数据");
        }
        validateCriteria(channelGovernanceVo.getEmptyCriteria(), "空值筛选条件不能为空", "筛选条件参数非法", channelGovernanceVo.getEmptyList());
        if (CollUtil.isNotEmpty(channelGovernanceVo.getEmptyList())) {
            Optional<String> first = channelGovernanceVo.getEmptyList().stream()
                    .filter(e -> StrUtil.isBlank(ChannelFieldEnum.getFiledName(e)))
                    .findFirst();
            if (first.isPresent()) {
                redisCache.deleteObject(REDIS_KEY_SYNC);
                throw new ServiceException(first.get() + "字段不存在");
            }
        }

    }

    /**
     * 校验规则条件
     *
     * @param channelGovernanceVo
     */
    private void validateRuleList(ChannelGovernanceVo channelGovernanceVo) {
        if (CollUtil.isNotEmpty(channelGovernanceVo.getRuleList())) {
            Optional<ChannelGovernanceRuleCriteriaVo> firstInvalidField = channelGovernanceVo.getRuleList().stream()
                    .filter(e -> StrUtil.isBlank(ChannelFieldEnum.getFiledName(e.getFieldName())))
                    .findFirst();
            if (firstInvalidField.isPresent()) {
                redisCache.deleteObject(REDIS_KEY_SYNC);
                throw new ServiceException(firstInvalidField.get().getFieldName() + "字段不存在");
            }
            Optional<ChannelGovernanceRuleCriteriaVo> firstInvalidField2 = channelGovernanceVo.getRuleList().stream()
                    .filter(e -> Integer.parseInt(e.getCriteria()) < 0 || Integer.parseInt(e.getCriteria()) > 7)
                    .findFirst();
            if (firstInvalidField2.isPresent()) {
                redisCache.deleteObject(REDIS_KEY_SYNC);
                throw new ServiceException(firstInvalidField2.get().getCriteria() + "筛选条件非法");
            }
        }
        validateCriteria(channelGovernanceVo.getRuleCriteria(), "规则条件不能为空", "筛选条件参数非法", channelGovernanceVo.getRuleList());
    }

    /**
     * 校验筛选条件
     *
     * @param criteria
     * @param emptyMessage
     * @param invalidMessage
     * @param list
     */
    private void validateCriteria(String criteria, String emptyMessage, String invalidMessage, List<?> list) {
        if (CollUtil.isNotEmpty(list) && StrUtil.isNotBlank(criteria) && !criteriaStrList.contains(criteria)) {
            redisCache.deleteObject(REDIS_KEY_SYNC);
            throw new ServiceException(invalidMessage);
        }
        if (CollUtil.isNotEmpty(list) && StrUtil.isBlank(criteria)) {
            redisCache.deleteObject(REDIS_KEY_SYNC);
            throw new ServiceException(emptyMessage);
        }

    }

}




